/* Copyright 2014 Jan Wolter */

#include "stack.h"
#include "pyramid.h"

/* Deal a card into a pyramid cell */
void pcdeal(PCell *pc, char code, Stack *deal)
{
    if (code == 'X') return;
    Card *c= popStack(deal);
    c->faceup= (code == 'U');
    pushStack(stacks+pc->stack, c);
}

/* Construct a pyramid.
 *   nrow is number of rows.
 *   row[] is an array of nrow strings. For TriPeaks it would be:
 *       "DXXDXXD"
 *       "DDXDDXDD"
 *       "DDDDDDDDD"
 *       "UUUUUUUUUU"
 *      Here 'X' indicates a missing card, 'D' a facedown card, and 'U' a
 *      faceup card.
 *    deal is the deck of cards to deal from
 */

void makePyramid(int nrow, char *row, Stack *deal)
{
    int id= 0;

    Pyramid *p= (Pyramid *)malloc(sizeof(Pyramid));
    p->len= (int *)malloc(nrow * sizeof(int));
    p->first= (int *)malloc(nrow * sizeof(int));

    /* Count up number of rows and total number of cells. Save row lengths */
    p->npyr= 0;
    p->nrow= 0;
    for (int i= 0; i < nrow; i++)
    {
	int ln= strlen(row[i]);
	if (i > 0 && (ln < p->len[p->nrow-1]-1 || ln > p->len[p->nrow-1]+1))
	{
	    fprintf(stderr,
		"Row %d length (%d) does not match previous row length (%d)\n",
		i, ln, p->len[p->nrow-1]);
	    exit(1);
	}

	if (i == 0 || ln != p->len[p->nrow-1])
	{
	    p->len[p->nrow]= ln;
	    p->first[p->nrow]= p->npyr;
	    p->npyr+= ln;
	    p->nrow++;
	}
    }

    p->pyr= (PCell **)malloc(p->npyr * sizeof(*PCell));

    int r= 0;
    for (int i= 0; i < nrow; i++)
    {
	int ln= strlen(row[i]);
	if (r > 0 && ln == p->len[r-1])
	{
	    /* Not a new row. Just more cards to deal into previous row */
	    for (int j= 0; j < ln; j++)
	    {
		PCell *pc= p->pyr[p->first[r-1]+j];
		pcdeal(pc, row[i][j], deal);
	    }
	    continue;
	}

	for (int j= 0; j < ln; j++)
	{
	    PCell *pc= p->pyr[id]= (PCell *)malloc(sizeof(PCell));
	    pc->id= id;
	    pc->depth= i;
	    pc->under[0]= pc->under[1]= NULL;

	    pc->next= pc->prev= NULL;

	    /* Set up pointers to covered cards */
	    if (i == 0)
		pc->over[0]= pc->over[1]= NULL;
	    else if (ln > len[i-1])
	    {
		pc->over[0]= (j == 0 ? NULL :
			p->pyr[id - len[i-1]] );

		pc->over[1]= (j == len[i-1] ? NULL :
			p->pyr[id - len[i-1] + 1] );
	    }
	    else
	    {
		pc->over[0]= p->pyr[id - len[i-1]];
		pc->over[1]= p->pyr[id - len[i-1] + 1];
	    }

	    /* Set up reciprocal pointers */
	    if (pc->over[0] != NULL)
		p->pyr[pc->over[0].id].under[1]= pc;
	    if (pc->over[1] != NULL)
		p->pyr[pc->over[1].id].under[0]= pc;

	    /* Deal a card into the cell */
	    pc->stack= newStack(PYRAMID, npyramid, 1, NULL,
		    pyramid_firstMove, pyramid_nextMove, NULL);
	    pcdeal(pc, row[i][j], deal);
	}
	r++;
    }
}
